package com.itheima.health.web;

import com.alibaba.fastjson.JSON;
import com.itheima.health.entity.Result;
import com.itheima.health.pojo.Permission;
import com.itheima.health.pojo.Role;
import com.itheima.health.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@WebFilter(filterName = "LonginCheckFilterHandler")
@Slf4j
public class LonginCheckFilterHandler implements Filter {

    /*
    进行路径拦截,和认证授权
     */
//定义一个字符串数组,数组中放被放行的路径
    private String[] unLoginAccessUrlList = new String[]{
            //这里是被放行的路径
            "/user/login",
            "/user/logout",
            "/common/**",
            "/mobile/**",// 移动端的无需登录都可以访问接口
    };

    //定义一个map集合,这个集合中装需要权限认证的路径,以及需要的权限关键字
    private Map<String, String> loginAuthUrlMap = new HashMap<>();

    private void initAuthUrlMap() {
        // 1.比如以下URI，需要用户有CHECKITEM_DELETE权限
        loginAuthUrlMap.put("/checkitem/delete", "CHECKITEM_DELETE");
        loginAuthUrlMap.put("/checkgroup/delete", "CHECKGROUP_DELETE");
        loginAuthUrlMap.put("/setmeal/delete", "SETMEAL_DELETE");
        // 2.比如访问report下的所有内容，需要用户有REPORT_VIEW权限，才可以访问
        loginAuthUrlMap.put("/report/**", "REPORT_VIEW");
    }

    //定义一个方法,,这个方法来判断,请求路径是否需要放行,返回值是Boolean类型,如果匹配,返回TRUE
    private boolean checkURI(String requestUrl) {
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        //遍历数组
        for (String needToBereleased : unLoginAccessUrlList) {
            if (antPathMatcher.match(needToBereleased,requestUrl)) {//匹配,放行
                return true;
            }
        }
        return false;
    }

    //在定义一个方法,判断该路径是否需要权限
    private boolean checkLoginAuthURI(String requestURL, User user) {//穿两个参数,一个是URL路径,一个是User类,将来从类中获取权限字段
        //new一个AntPathMatcher,路径资源匹配器
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        //遍历set集合中的key,如果请求路径和se集合中的key匹配,说明需要进行权限认证
        Set<String> setUrl = loginAuthUrlMap.keySet();//setUrl,是set集合中所有的键,也是所有需要权限的路径
        //定义一个容器,容器初始化值为null
        String container = null;
        for (String oneSetUrl : setUrl) {//oneSetUrl是遍历后,拿到每一个权限路径
            if (antPathMatcher.match(requestURL, oneSetUrl)) {
                container = oneSetUrl;//将需要权限的路径赋值给container
            }
        }
        //判断container是否有数据,有数据说明,需要进行权限认证,没有数据,直接放行
        if (container == null) {//这个路径不是权限路径,放行
            return true;
        }
        //下面操作是有数据,说明这是一个权限路径,不能放行,需要权限认证
        //根据键找值,找到这个路径权限需要的权限关键字
        String requiredPermissionKeywords = loginAuthUrlMap.get(container);//requiredPermissionKeywords : 需要的权限关键字
        //查看用户有没有这个权限
        Set<Role> allRoles = user.getRoles();//获取这个用户的所有角色
        for (Role oneRole : allRoles) {
            //拿到每一个角色,查看每一个角色中的权限
            Set<Permission> oneRoleCorrespondAllPermissions = oneRole.getPermissions();//oneRoleCorrespondAllPermissions : 一个角色对应的所有权限
            for (Permission onePermission : oneRoleCorrespondAllPermissions) {//onePermission  : 一个权限
                if (requiredPermissionKeywords.equals(onePermission.getKeyword())) {//说明有权限,返回true
                    return true;
                }
            }
        }
//        //查看用户有没有这个权限
//        Set<Role> roles = user.getRoles();
//        for (Role role : roles) {
//            Set<Permission> permissions = role.getPermissions();
//            for (Permission permission : permissions) {
//                if(permission.equals(requiredPermissionKeywords)){
//                    return true;
//                }
//            }
//        }
        log.info("[权限检查过滤器],当前用户匹配权限不匹配，未通过");
        return false;
    }


    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //向下转型
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //获取请求地址
        String requestURI = request.getRequestURI();
        //判断URI是否可以无需登录，即可访问
        boolean check = checkURI(requestURI);
        if (check) {//check为true,放行
            chain.doFilter(request, response);//放行语句
            log.info("后端用户登陆成功");
            return;//到这就停止了
        }

        //如果路径匹配不上,就判断当前会话中,是否有这个用户
        //从域中获取用户名
        if (request.getSession().getAttribute("user") != null) {//说明用户在当前会话,代表用户登陆过
            User user = (User) request.getSession().getAttribute("user");
            log.info("用户已登录,接下来判断是否需要权限认证");
            boolean isLoginAuth = checkLoginAuthURI(requestURI, user);//isLoginAuth  :判断用户是否有权限的结果
            if (isLoginAuth) {//true,有权限,放行
                chain.doFilter(request, response);
            }
            //下面操作是,用户登录了,但是没有权限
            else {
                //// 已登录过，但是访问的资源没有权限，前端处理错误信息显示,虽然你登录了,但是你没有权限
                response.setContentType("application/json; charset=UTF-8");//以JSON形式给前端
                response.getWriter().write(JSON.toJSONString(new Result(false, "没有操作权限")));
            }
        } else if (request.getSession().getAttribute("member") != null) {
            log.info("[权限检查过滤器],移动端用户登录，允许放行");
            chain.doFilter(request,response);
        }else {
            response.setContentType("application/json; charset=UTF-8");//以JSON形式给前端
            response.getWriter().write(JSON.toJSONString(new Result(false, "请重新登录")));
        }

    }


    public void destroy() {
    }

    public void init(FilterConfig config) throws ServletException {
        initAuthUrlMap();
    }


}
